package com.jmb.api.web.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jmb.api.common.exception.WebApiException;
import com.jmb.api.common.result.ResultCodeEnum;
import com.jmb.api.entity.DataFactory;
import com.jmb.api.entity.Db;
import com.jmb.api.entity.DbConnection;
import com.jmb.api.enums.FactoryType;
import com.jmb.api.vo.DataFactory.DataFactoryInfoVO;
import com.jmb.api.vo.DataFactory.DataFactoryQueryVO;
import com.jmb.api.vo.DataFactory.DataFactoryVO;
import com.jmb.api.web.env.Env;
import com.jmb.api.web.mapper.DataFactoryMapper;
import com.jmb.api.web.service.DataFactoryService;
import com.jmb.api.web.service.DbService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.jmb.api.common.utils.JdbcUtil;

import java.security.DomainLoadStoreParameter;
import java.util.ArrayList;
import java.util.concurrent.CompletableFuture;


@Slf4j
@Service
public class DataFactoryServiceImpl extends ServiceImpl<DataFactoryMapper, DataFactory>
    implements DataFactoryService {

    @Autowired
    private DataFactoryMapper dataFactoryMapper;
    @Autowired
    private DbService dbService;
    @Autowired
    private Env env;

    @Override
    public void saveOrUpdateDataFactory(DataFactory dataFactory) {
        boolean isUpdate = dataFactory.getId() != null;
        log.info("开始执行校验逻辑");
        dataFactory = checkDataFactory(dataFactory);
        log.info("结束执行校验逻辑{}",dataFactory);
        // 查询数据库名称是否存在
        LambdaQueryWrapper<DataFactory> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DataFactory::getName, dataFactory.getName());

        // 判断是修改操作，需要排除当前数据源本身
        if (isUpdate){
            queryWrapper.ne(DataFactory::getId, dataFactory.getId());
        }
        // 查询数据
        DataFactory factory = dataFactoryMapper.selectOne(queryWrapper);
        // 判断是否存在相同名称
        if (factory != null){
            throw new WebApiException(ResultCodeEnum.web_Db_EXIST_ERROR);
        }
        // 执行保存或修改
        log.info("开始执行保存或修改{}",dataFactory);
        super.saveOrUpdate(dataFactory);
    }

    // 执行数据源

    @Override
    public Long executeDataFactory(Long id) {
        DataFactory dataFactory = this.getById(id);
        // 获取type类型进行判断
        Integer type = dataFactory.getType();
        // 获取失败重试
        boolean failedStop = dataFactory.getFailedStop() == 0;
        // 判断执行方式
        Integer executeType = dataFactory.getExecuteType(); // 执行方式 0并行 1串行
        // 获取执行次数
        Integer times = dataFactory.getTimes();
        // 获取时间
        long begin = System.currentTimeMillis();
        switch (type){
            case 0: // SQL
                executeSql(dataFactory,times,failedStop);
                break;
            case 1: // 接口
                executeInterface(dataFactory,times,executeType,null,failedStop);
            default:
                throw new WebApiException(ResultCodeEnum.DATA_ERROR);
        }
        long end = System.currentTimeMillis();
        log.info("执行完毕，耗时{}毫秒",end-begin);
        return end-begin;
    }
    // 执行Sql
    public void executeSql(DataFactory dataFactory,Integer times,boolean failedStop){
        String sql = dataFactory.getSqlStr();
        Integer sqlRunDev = dataFactory.getSqlRunDev();
        Integer dbId = dataFactory.getSqlDbId();
        Db db = dbService.getById(dbId);
        DbConnection datasource = env.datasource(db, sqlRunDev);
        String url = datasource.getUrl();
        String username = datasource.getUsername();
        String password = datasource.getPassword();

        // todo：对Sql进行参数化或合法性校验，防止Sql注入
        for (int i = 0; i < times; i++) {
            log.info("开始执行第{}次{}",i+1,sql);
            JdbcUtil.runScript(sql,url,username,password,failedStop);
        }
    }

    // 执行接口
    // todo 代码待完善，需要完善补充
    public void executeInterface(DataFactory factory,Integer times,Integer executeType,String executor, boolean failedStop){
        Integer suiteId = factory.getInterfaceSuiteId();
        if (executeType == 1){
            // 串行
            for (int i = 0; i < times; i++) {
                // 执行接口 待实现

            }
        }else {
            // 并行
            ArrayList<CompletableFuture> completableFutures = new ArrayList<>();
            for (int i = 0; i < times; i++) {
                // 执行接口 待实现
                CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                    // 执行接口 待实现
                });
                completableFutures.add(future);
            }
        }
    }

    /**
     * 数据源列表
     */
    @Override
    public IPage<DataFactoryInfoVO> listDataFactory(IPage<DataFactoryInfoVO> page, DataFactoryQueryVO dataFactoryQueryVO) {
        return dataFactoryMapper.listDataFactory(page,dataFactoryQueryVO);
    }

    // 提取一个公共方法，对type做判断
    public DataFactory checkDataFactory(DataFactory dataFactory){
        if (dataFactory.getType() == null){
            throw new WebApiException(ResultCodeEnum.DATA_ERROR);
        }
        if (dataFactory.getType() ==0){
            dataFactory.setInterfaceSuiteId( null);
            dataFactory.setUiSuiteId( null);
        }
        else if (dataFactory.getType() ==1){
            dataFactory.setSqlDbId( null);
            dataFactory.setSqlRunDev( null);
            dataFactory.setSqlStr( null);
            dataFactory.setUiSuiteId( null);
        }
        return dataFactory;
    }
}




